import axios, {
  type AxiosRequestConfig,
  type AxiosInstance,
  type AxiosResponse,
  InternalAxiosRequestConfig,
  AxiosError,
  HttpStatusCode,
  CreateAxiosDefaults,
} from 'axios';
// import { type URLTYPE } from './api';
import { STORAGE } from '@/utils';

// 上传文件类型
type UploadRequestConfig = Omit<AxiosRequestConfig, 'url' | 'data'>;
// 上传文件参数类型
interface UploadFileItem {
  name: string;
  value: string | Blob;
}
const requests = new Map<string, AbortController>();
// 获取请求的唯一标识
const getReqKey = (config: InternalAxiosRequestConfig) => {
  if (config.url) {
    return config.url + config.method + config.data;
  } else {
    return null;
  }
};

// 请求类型
type ConfigWithURLType = AxiosRequestConfig;
// 请求类
class HttpRequest {
  service: AxiosInstance;
  constructor() {
    const config: CreateAxiosDefaults = {
      timeout: 5 * 1000,
      baseURL: import.meta.env.VITE_APP_BASEURL,
    };

    this.service = axios.create(config);
    // 拦截器
    // 请求拦截器
    this.service.interceptors.request.use(
      (config: InternalAxiosRequestConfig) => {
        // 如果有token, 将其传给header
        if (sessionStorage.getItem(STORAGE.TOKEN)) {
          config.headers.Authorization =
            'Bearer ' + sessionStorage.getItem(STORAGE.TOKEN);
        }
        // 如果包含了请求
        const key = getReqKey(config);
        // 是否存在该请求
        if (key && requests.has(key)) {
          const abortController = requests.get(key);
          abortController?.abort();
        }
        // 取消请求
        const controls = new AbortController();
        config.signal = controls.signal;
        key && requests.set(key, controls);
        return config;
      },
      (error: AxiosError) => {
        return Promise.reject(error);
      },
      {
        synchronous: false,
        runWhen: () => {
          return true;
        },
      },
    );
    // 响应拦截器
    this.service.interceptors.response.use(
      (response: AxiosResponse) => {
        // 正确
        if (response.status === HttpStatusCode.Ok) {
          const key = getReqKey(response.config);
          if (key && requests.get(key)) {
            requests.delete(key);
          }
          return response;
          // 错误
        } else {
          switch (response.status) {
            case HttpStatusCode.NotFound:
              // nofound逻辑
              break;
            case HttpStatusCode.BadRequest:
              // badRequest逻辑
              break;
          }
          // todo看后台如何定义错误数据格式
          return Promise.reject(response.data);
        }
      },
      (error: AxiosError) => {
        return Promise.reject(error);
      },
    );
  }
  // 请求
  // T 表示返回的数据类型
  request<T>(config: AxiosRequestConfig): Promise<AxiosResponse<T>['data']> {
    return new Promise((resolve, reject) => {
      return this.service
        .request<T>(config)
        .then((res: AxiosResponse<T>) => {
          resolve(res.data);
        })
        .catch((err) => {
          reject(err);
        });
    });
  }
  // 请求方法
  get<T>(config: ConfigWithURLType): Promise<T> {
    return this.request<T>({ method: 'GET', ...config });
  }
  post<T>(config: ConfigWithURLType): Promise<T> {
    return this.request<T>({ method: 'POST', ...config });
  }
  put<T>(config: ConfigWithURLType): Promise<T> {
    return this.request<T>({ method: 'PUT', ...config });
  }

  upload<T = string>(
    fileItem: UploadFileItem,
    config?: UploadRequestConfig,
  ): Promise<T> | null {
    if (!import.meta.env.VITE_APP_UPLOADURL) return null;

    let _config: UploadRequestConfig;
    if (config) {
      config.headers && (config.headers['Content-Type'] = 'multiple/form-data');
      _config = config;
    } else {
      _config = {
        headers: {
          'Content-Type': 'multiple/form-data',
        },
      };
    }

    const fd = new FormData();
    fd.append(fileItem.name, fileItem.value);

    return this.request<T>({
      url: import.meta.env.VITE_APP_UPLOADURL,
      data: fd,
      ..._config,
    });
  }
}
const httpRequest = new HttpRequest();

export default httpRequest;
